package com.ruoyi.basedata.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctg.ag.sdk.biz.AepDeviceManagementClient;
import com.ctg.ag.sdk.biz.aep_device_management.CreateDeviceRequest;
import com.ctg.ag.sdk.biz.aep_device_management.CreateDeviceResponse;
import com.ruoyi.basedata.domain.*;
import com.ruoyi.basedata.domain.vo.TerminalsDbProtocol;
import com.ruoyi.basedata.mapper.*;
import com.ruoyi.basedata.service.ITerminalsDbService;
import com.ruoyi.basedata.service.ITerminalsXbService;
import com.ruoyi.basedata.wxentity.Terminals;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.SnowflakeUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Validator;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 大档案Service业务层处理
 *
 * @author ruoyi
 * @date 2023-09-07
 */
@Service
@Slf4j
public class TerminalsDbServiceImpl extends ServiceImpl<TerminalsDbMapper, TerminalsDb> implements ITerminalsDbService {
    @Autowired
    private TerminalsDbMapper terminalsDbMapper;
    @Autowired
    private ReplaceMapper replaceMapper;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    protected Validator validator;
    @Autowired
    private ITerminalsDbService terminalsDbService;
    @Autowired(required = false)
    private RedisCache redisCache;
    @Autowired
    private ITerminalsXbService terminalsXbService;
    @Autowired
    private ProtocolMapper protocolMapper;

    @Autowired
    private MeterSheetsMapper meterSheetsMapper;
    @Autowired
    private AccountMapper accountMapper;
    @Resource
    private Environment env;

    @Value("${system-params.appKey}")
    public String appKey;
    //    @Value("${system-params.appSecret}")
    @Value("${system-params.appSecret}")
    private String appSecret;
    @Value("${system-params.masterKeyDb}")
    private String masterKey;
    @Value("${system-params.productIdDb}")
    private String productId;

    @Value("${system-params.dongJianMasterKeyDb}")
    private String dongJianMasterKey;

    @Value("${system-params.dongJianProductIdDb}")
    private String dongJianProductId;


    private static final String FACTORY_CODE = "_1002";

    /**
     * 大表注册协议id
     */
    private static final String PROTOCOL_DB = "1";

    /**
     * 查询大档案
     *
     * @param Id 大档案主键
     * @return 大档案
     */
    @Override
    public TerminalsDb selectTerminalsDbById(Long Id) {
        return terminalsDbMapper.selectTerminalsDbById(Id);
    }

    /**
     * 根据通讯地址、厂家编码查询设备
     *
     * @param terminalsDb
     * @return
     */
    @Override
    public List<TerminalsDbProtocol> selectTerminalsDbProtocolList(TerminalsDb terminalsDb) {
        return terminalsDbMapper.selectTerminalsDbProtocolList(terminalsDb);
    }

    /**
     * 查询大档案列表
     *
     * @param terminalsDb 大档案
     * @return 大档案
     */
    @Override
    public List<TerminalsDb> selectTerminalsDbList(TerminalsDb terminalsDb) {
        return terminalsDbMapper.selectTerminalsDbList(terminalsDb);
    }

    /**
     * 新增大档案
     *
     * @param terminalsDb 大档案
     * @return 结果
     */
    @Override
    public int insertTerminalsDb(TerminalsDb terminalsDb) {
        return terminalsDbMapper.insertTerminalsDb(terminalsDb);
    }

    /**
     * 修改大档案
     *
     * @param terminalsDb 大档案
     * @return 结果
     */
    @Override
    public int updateTerminalsDb(TerminalsDb terminalsDb) {
        int res =  terminalsDbMapper.updateTerminalsDb(terminalsDb);
        if(res > 0){
            TerminalsDbProtocol terminalsDbNew = terminalsDbService.selectTerminalsDbProtocolList(terminalsDb).get(0);
//            TerminalsDbProtocol terminalsDbNew = (TerminalsDbProtocol)terminalsDb;//转成存储到redis里的设备类型
//            TerminalsDbProtocol redisTerminalsDb = redisCache.getCacheMapValue(RedisKeyName.terminalDbInfo+terminalsDb.getSupplierId(), terminalsDb.getCommunicateAddress());
//            terminalsDbNew.setClassName(redisTerminalsDb.getClassName());
//            terminalsDbNew.setMethodName(redisTerminalsDb.getMethodName());
//            terminalsDbNew.setProtocol_name(redisTerminalsDb.getProtocol_name());
            redisCache.setCacheMapValue(RedisKeyName.terminalDbInfo+terminalsDb.getSupplierId(), terminalsDb.getCommunicateAddress(), terminalsDbNew);
        }
        return res;
    }

    /**
     * 批量删除大档案
     *
     * @param Ids 需要删除的大档案主键
     * @return 结果
     */
    @Override
    public int deleteTerminalsDbByIds(Long[] Ids) {
        List<TerminalsDb> terminalsDbs = terminalsDbMapper.selectBatchIds(Arrays.asList(Ids));
        int rows = terminalsDbMapper.deleteTerminalsDbByIds(Ids);
        List<String> deviceIds = terminalsDbs.stream().map(TerminalsDb::getDeviceId).collect(Collectors.toList());
        JSONObject jsonObject;
        try {
            jsonObject = terminalsXbService.deleteGuoXinDeviceInAep(appKey, appSecret, masterKey, deviceIds, productId);
            log.info(jsonObject.toJSONString());
        } catch (Exception e) {
            log.error("取消注册失败", e);
        }
        return rows;
    }

    /**
     * 删除大档案信息
     *
     * @param Id 大档案主键
     * @return 结果
     */
    @Override
    public int deleteTerminalsDbById(Long Id) {
        return terminalsDbMapper.deleteById(Id);
    }

    /**
     * 换表
     *
     * @param terminalsDb
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeTerminalDb(TerminalsDb terminalsDb) {
        try {
            boolean flag = false;
            TerminalsDb old = terminalsDbMapper.selectById(terminalsDb.getId());
            //更新原表为停用状态
            terminalsDb.setTerminalMark(0);
            int i = terminalsDbMapper.updateTerminalMark(terminalsDb.getId());
            //更新换表记录
            LoginUser loginUser = SecurityUtils.getLoginUser();
            Replace rep = Replace.builder().tenantId(terminalsDb.getTenantId()).changeTime(new Date()).terminalClassify(1)
                    .oldTerminalId(terminalsDb.getTerminalId()).newTerminalId(terminalsDb.getTerminalIdNew())
                    .newBaseReading(terminalsDb.getBaseReadingNew()).oldSettlementReading(terminalsDb.getBaseReading())
                    .operator(loginUser.getUsername()).remark(terminalsDb.getChangeRemark()).sheetsCode(terminalsDb.getSheetsCode())
                    .sheetsId(terminalsDb.getSheetsId()).oldSupplierId(old.getSupplierId()).newSupplierId(terminalsDb.getSupplierId()).build();
            replaceMapper.insertReplace(rep);

            //新增一条表档案
            terminalsDb.setTerminalMark(1);
            terminalsDb.setImei(terminalsDb.getImeiNew());
            terminalsDb.setTerminalId(terminalsDb.getTerminalIdNew());
            terminalsDb.setBaseReading(terminalsDb.getBaseReadingNew());
            terminalsDb.setId(null);
            terminalsDb.setCreateTime(new Date());
            if(terminalsDb.getSheetsId() == null){
                terminalsDb.setSheetsId(old.getSheetsId());
            }
            if(StringUtils.isBlank(terminalsDb.getSheetsCode())){
                terminalsDb.setSheetsCode(old.getSheetsCode());
            }
            if(StringUtils.isBlank(terminalsDb.getSupplierId())){
                terminalsDb.setSupplierId(old.getSupplierId());
            }
            int k = terminalsDbMapper.insert(terminalsDb);
            if (i > 0 && k > 0) {
                flag = true;
            }

            return flag;
        } catch (Exception e) {
            log.error("换表失败", e);
            return false;
        }
    }


    @Override
    public String importUser(List<TerminalsDb> list, Boolean isUpdateSupport, String operName) {
        if (StringUtils.isNull(list) || list.size() == 0) {
            throw new ServiceException("导入数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (TerminalsDb terminalsDb : list) {
            try {
                // 验证是否存在这个表档案
                List<TerminalsDb> terminalsDbs = terminalsDbService.list(new QueryWrapper<TerminalsDb>().eq("terminal_id", terminalsDb.getTerminalId()).eq("del_flag", 0));
                if (null != terminalsDbs && terminalsDbs.size() > 0) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsDb.getTerminalId()).append(" 已存在");
                } else {
                    SnowflakeUtils idWorker = new SnowflakeUtils(0, 0);
                    String locationFlag = idWorker.nextId() + "";
                    terminalsDb.setLocationNb(locationFlag);
                    if (StringUtils.isAnyBlank(terminalsDb.getSheetsCode())||terminalsDb.getProtocolId()==null || terminalsDb.getSupplierId() == null){
                        failureNum++;
                        failureMsg.append("<br/>").append(failureNum).append("、协议ID、区域编号、厂家编号均不能为空 ");
                        continue;
                    }
                    Protocol protocol = protocolMapper.selectOne(new LambdaQueryWrapper<Protocol>().eq(Protocol::getProtocolId,terminalsDb.getProtocolId()).eq(Protocol::getTerminalType,1).last("limit 1"));
                    if (protocol != null){
                        terminalsDb.setProtocolName(protocol.getProtocolName());
                    }else{
                        failureNum++;
                        failureMsg.append("<br/>").append(failureNum).append("、协议ID ").append(terminalsDb.getProtocolId()).append(" 不存在");
                        continue;
                    }
                    MeterSheets sheets = meterSheetsMapper.selectOne(new LambdaQueryWrapper<MeterSheets>().eq(MeterSheets::getSheetsCode,terminalsDb.getSheetsCode()).eq(MeterSheets::getDelFlag,0).last("limit 1"));
                    if (sheets != null){
                        terminalsDb.setSheetsId(Math.toIntExact(sheets.getId()));
                    }else{
                        failureNum++;
                        failureMsg.append("<br/>").append(failureNum).append("、区域编号 ").append(terminalsDb.getSheetsCode()).append(" 不存在");
                        continue;
                    }
                    int resCount = terminalsDbService.insertTerminalsDb(terminalsDb);
                    if(resCount>0){
                        try {
                            List<TerminalsDbProtocol> terminalsDbProtocols = terminalsDbService.selectTerminalsDbProtocolList(terminalsDb);
                            redisCache.setCacheMapValue(RedisKeyName.terminalDbInfo + terminalsDb.getSupplierId(), terminalsDb.getCommunicateAddress(), terminalsDbProtocols.get(0));
                        }catch (Exception e){
                            log.error("大表插入redis失败,设备编号：{}",terminalsDb.getTerminalId());
                            log.error(ExceptionUtil.getExceptionMessage(e));
                        }
                    }
                    successNum++;
                    successMsg.append("<br/>").append(successNum).append("、设备编号 ").append(terminalsDb.getTerminalId()).append(" 更新成功");

                    try {
                        // if (StringUtils.isBlank(terminalsDb.getProtocolId()) || !PROTOCOL_DB.equals(terminalsDb.getProtocolId())) {
                        //     failureNum++;
                        //     failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsDb.getTerminalId()).append(" 导入成功，协议错误,不能注册");
                        // } else {

                            JSONObject responseBody = null;
                            //做一个sign标识来确定走的是哪一个的返回值
                            String sign = null;
                            if (terminalsDb.getSignPlatform() == null){
                                failureNum++;
                                failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsDb.getTerminalId()).append("请选择正确的注册平台");
//                                throw new RuntimeException("请选择OneNET平台或aep平台");
                            }
                            //用sign来判断它走aep还是onenet
                            if (terminalsDb.getSignPlatform() == 2) {
                                sign = "OneNET";
                                responseBody = createDeviceInOneNet(terminalsDb);
                            }else if (terminalsDb.getSignPlatform() == 1) {
                                sign = "AEP";
                                responseBody = createGuoXinDeviceInAep(appKey, appSecret, null, terminalsDb);
                            }else if(terminalsDb.getSignPlatform() == 3){
                                sign = "netty";
                            }
                            //aep返回码是code，onenet返回码是errno，所以分来来写
                            if (responseBody == null  && sign == null) {
                                failureNum++;
                                failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsDb.getTerminalId()).append("导入成功,发送注册请求到物联网平台时出现错误，注册失败");
                            } else {
                                if ("AEP".equals(sign)){
                                    if (Integer.parseInt(responseBody.getString("code")) == 0) {
                                        successMsg.append(",").append(sign).append("平台注册成功");
                                        String deviceId = JSONObject.parseObject(responseBody.getString("result")).getString("deviceId");
                                        TerminalsDb terminalsDb1 = terminalsDbMapper.selectOne(new LambdaQueryWrapper<TerminalsDb>()
                                                .eq(TerminalsDb::getImei, terminalsDb.getImei()).eq(TerminalsDb::getDelFlag,0));
                                        terminalsDb1.setDeviceId(deviceId);
                                        terminalsDbMapper.updateTerminalsDb(terminalsDb1);
                                    } else {
                                        failureNum++;
                                        failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsDb.getTerminalId()).append(" 导入成功,").append(sign).append("平台注册失败 ").append(responseBody.getString("msg"));
                                    }
                                }

                                if ("OneNET".equals(sign)){
                                    if (Integer.parseInt(responseBody.getString("errno")) == 0) {
                                        successMsg.append(",").append(sign).append("平台注册成功");
                                        String deviceId = JSONObject.parseObject(responseBody.getString("data")).getString("device_id");
                                        TerminalsDb terminalsDb1 = terminalsDbMapper.selectOne(new LambdaQueryWrapper<TerminalsDb>()
                                                .eq(TerminalsDb::getImei, terminalsDb.getImei()));
                                        terminalsDb1.setDeviceId(deviceId);
                                        terminalsDbMapper.updateTerminalsDb(terminalsDb1);
                                    } else {
                                        failureNum++;
                                        failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsDb.getTerminalId()).append(" 导入成功，").append(sign).append("平台注册失败 ").append(responseBody.getString("error"));
                                    }
                                }
                            }
                        // }
                    } catch (Exception e) {
                        failureNum++;
                        log.error("注册失败", e);
                        failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsDb.getTerminalId()).append(" 导入成功，物联网平台注册失败");
                    }
                }

            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、设备编号 " + terminalsDb.getTerminalId() + " 导入失败：";
                failureMsg.append(msg).append(e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public List<Terminals> selectWXTerminalsDbById(Long id) {
        return terminalsDbMapper.selectWXTerminalsDbById(id);
    }

    @Override
    public JSONObject createGuoXinDeviceInAep(String appKey, String appSecret, String masterKeys, TerminalsDb terminalsDb) {
        AepDeviceManagementClient client = AepDeviceManagementClient.newClient()
                .appKey(appKey).appSecret(appSecret)
                .build();
        try {
            CreateDeviceRequest request = new CreateDeviceRequest();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("deviceName", terminalsDb.getCommunicateAddress());
            jsonObject.put("deviceSn", terminalsDb.getImei());
            jsonObject.put("imei", terminalsDb.getImei());
            jsonObject.put("operator", SecurityUtils.getLoginUser().getUsername());
            if ("1015".equals(terminalsDb.getSupplierId())) {
                jsonObject.put("productId", dongJianProductId);
                request.setParamMasterKey(dongJianMasterKey);
            }else {
                jsonObject.put("productId", productId);
                request.setParamMasterKey(masterKey);
            }
            Map<String, Object> other = new HashMap<>(2);
            other.put("autoObserver", 0);
            jsonObject.put("other", other);
//            request.setParamMasterKey(masterKey);
            request.setBody(jsonObject.toString().getBytes());
            CreateDeviceResponse createDeviceResponse = client.CreateDevice(request);
            System.out.println(createDeviceResponse);
            return JSONObject.parseObject(new String(createDeviceResponse.getBody(), StandardCharsets.UTF_8));
        } catch (Exception e) {
            log.error("AEP平台注册失败", e);
            return null;
        } finally {
            client.shutdown();
        }
    }

    @Override
    public JSONObject createDeviceInOneNet(TerminalsDb terminalsDb) throws Exception {
        if(StringUtils.isBlank(terminalsDb.getImsi())) {
            return null;
        }
        JSONObject jsonOb = new JSONObject();
        // imsi&imei
        jsonOb.put(terminalsDb.getImei(), terminalsDb.getImsi());
        JSONObject jsonObject = new JSONObject();
        // OneNET接口协议,必须
        jsonObject.put("protocol", "LWM2M");
        // imei,imsi码,必须
        jsonObject.put("auth_info", jsonOb);
        // 设备名称,必须
        jsonObject.put("title", terminalsDb.getCommunicateAddress());
        // 添加设备的接口地址
        String url = "https://api.heclouds.com/devices";
        String sendPost = HttpUtils.sendPostWithToken(url, jsonObject);
        JSONObject json = JSONObject.parseObject(sendPost);
        System.out.println(json.toString());
        Integer errno = json.getInteger("errno");
        String error = json.getString("error");
        if (errno != null) {
            if (errno == 0 && "succ".equals(error)) {
                return json;
            }
            if (errno == 6) {
                return json;
            }
        }
        return null;
    }

    @Override
    public void updateDeviceId(TerminalsDb terminalsDb) {
        terminalsDbMapper.updateTerminalsDb(terminalsDb);
        TerminalsDbProtocol terminalsDbProtocol = new TerminalsDbProtocol();
        terminalsDbProtocol.setImei(terminalsDb.getImei());
        List<TerminalsDbProtocol> terminalsDbProtocols = selectTerminalsDbProtocolList(terminalsDbProtocol);
        if (terminalsDbProtocols.size() != 0) {
            redisCache.setCacheMapValue(RedisKeyName.terminalDbInfo + terminalsDbProtocols.get(0).getSupplierId(), terminalsDbProtocols.get(0).getCommunicateAddress(), terminalsDbProtocols.get(0));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelTerminal(Long id) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        TerminalsDb terminalsDb = terminalsDbMapper.selectById(id);
        TerminalsDb update = new TerminalsDb();
        update.setTerminalMark(0);
        update.setId(id);
        update.setUpdateBy(user.getUserName());
        update.setUpdateTime(new Date());
        int row1 = terminalsDbMapper.updateTerminalsDb(update);
        Account account = Account.builder()
                .sheetsCode(terminalsDb.getSheetsCode())
                .terminalId(terminalsDb.getTerminalId())
                .userId(terminalsDb.getUserId())
                .terminalType(1L)
                .operator(user.getUserName())
                .locationNb(terminalsDb.getLocationNb())
                .tenantId(terminalsDb.getTenantId())
                .createTime(new Date())
                .build();
        int row2 = accountMapper.insertAccount(account);
        return row1 > 0 && row2 > 0;
    }



}


